package tabbedCanvas;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.geom.AffineTransform;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

/**
 * The turtle layer is where all the turtle is being drawn. This layer will refresh every single
 * time a new movement is being drawn. This layer contains the current location, orientation, and 
 * "activeness" of all turtles. There will be one turtleLayer per tab.
 * @author KevinWang
 *
 */
public class TurtleLayer extends CenteredLayer {


    private static final long serialVersionUID = 1L;
    private Map<Integer, Point> turtleLocations = new HashMap<Integer, Point>();
    private Map<Integer, Double> turtleOrientation = new HashMap<Integer, Double>();
    private List<Integer> activeTurtleList = new ArrayList<Integer>();
    private Image turtleImage;
    //TODO need to put this in resource bundle
    private String filePath = "src/tabbedCanvas/default.png";

    public TurtleLayer(Dimension dimension){
        super(dimension);
        updateTurtleImage(filePath);
    }

    /**
     * initialized new turtle
     * @return return turtle ID
     */
    protected int createTurtle(int ID){
        int turtleID = new Integer(ID);
        turtleLocations.put(turtleID, new Point(0,0));
        turtleOrientation.put(turtleID, 0.0);
        updateActiveTurtleList(turtleID);
        return ID;
    }

    /**
     * update the active turtleList so that the turtle that is updated later will be placed in 
     * a higher index location
     * @param turtleID
     */
    private void updateActiveTurtleList(int turtleID) {
        activeTurtleList.remove((Object)turtleID);
        activeTurtleList.add(turtleID);
    }

    /**
     * move turtle with given ID to location x,y
     * @param ID -ID of the turtle
     * @param x- x coordinate
     * @param y- y coordinate
     * @param degrees - orientation of the turtle
     */
    public void move(int ID, int x, int y, double degrees){
        if(!turtleLocations.containsKey(ID)){
            createTurtle(ID);
        }
        updateActiveTurtleList(ID);
        if(outOfBounds(x,y)){
            //TODO return error?
        }
        turtleLocations.get(ID).setLocation(x, y);
        turtleOrientation.put(ID, degrees);
        repaint();
    }

    /**
     * check to see if point (x,y) is out of bounds
     * @param x - x coordinate
     * @param y - y coordinate
     * @return
     */
    private boolean outOfBounds(int x, int y) {
        return Math.abs(x)>dimension.getWidth()/2 || Math.abs(y)>dimension.getHeight()/2;
    }

    /**
     * override paintComponent method so that it will draw turtles
     */
    @Override public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for(int ID : activeTurtleList){
            drawTurtle(g, ID);
        }
    }

    /**
     * draw turtle using Graphics2D and using rotation to make the images turn
     * @param g
     */
    private void drawTurtle(Graphics g, int ID){
        Graphics2D g2D = (Graphics2D)g;
        
        //store original Xform
        AffineTransform origXform = g2D.getTransform();
        //Clone to create new Xform
        AffineTransform newXform = (AffineTransform)(origXform.clone());
        
        Point location = turtleLocations.get(ID);
        newXform.rotate(Math.toRadians(turtleOrientation.get(ID)),xCenter + location.x, yCenter - location.y);
        g2D.setTransform(newXform);
        Point imageLocation = getImageLocation(ID);
        g2D.drawImage(turtleImage,imageLocation.x, imageLocation.y, this);
        g2D.setTransform(origXform);
        
    }
    
    /**
     * compute the correct coordinates to draw the image so that the center of the image
     * would be at the desired location
     * @param ID
     * @return
     */
    private Point getImageLocation(int ID){
        int x = xCenter+turtleLocations.get(ID).x-turtleImage.getWidth(null)/2;
        int y = yCenter-turtleLocations.get(ID).y-turtleImage.getHeight(null)/2;
        return new Point(x, y);
    }

    /**
     * clears the canvas
     */
    public void clear(){
        super.paintComponent(this.getGraphics());
    }

    /**
     * remove the turtle with the given ID so that it will not be shown
     * @param ID - ID of turtle to be deactivated
     */
    public void hideTurtle(int ID){
        Iterator<Integer> it = activeTurtleList.iterator();
        while(it.hasNext()){
            if(it.next()==ID){
                it.remove();
                break;
            }
        }
        repaint();
    }

    /**
     * resize the canvas
     */
    public void resize(Dimension dimension){
        this.dimension=dimension;
        setPreferredSize(dimension);
        setCenter(dimension);
        setBounds(0,0, (int)dimension.getWidth(), (int)dimension.getHeight());

    }
    
    /**
     * change the turtleImage by obtain image from String path
     * @param path: path of the image
     */
    public void updateTurtleImage(String path){
        InputStream is = null;
        try {
            is = new BufferedInputStream( new FileInputStream(filePath));
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        }
        try {
            turtleImage = ImageIO.read(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * set the turtle with given ID to active
     * @param ID - ID of the turtle to be activated
     */
    public void setActive(int ID){
        updateActiveTurtleList(ID);
    }
}
